package com.mengzhilan.context;

import com.mengzhilan.base.AnnotationKeys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xlp.assertion.AssertUtils;
import org.xlp.mvc.context.ApplicationContext;
import org.xlp.mvc.context.ApplicationContextException;
import org.xlp.mvc.context.ApplicationContextUtils;
import org.xlp.scanner.pkg.ConfigurationScannerPkg;
import org.xlp.scanner.pkg.ScannerAnnotationParser;
import org.xlp.scanner.pkg.ScannerPkg;
import org.xlp.stopwatch.StopWatch;

import java.lang.annotation.Annotation;
import java.util.*;

/**
 * Description: 应用上下文
 * <br/>date: 2023/12/28 16:35
 *
 * @version 1.0
 * @author: xlp
 */
public class MZLApplicationContext extends ApplicationContext {
    private final static Logger LOGGER = LoggerFactory.getLogger(MZLApplicationContext.class);

    /**
     * 存储类注解和类集合的映射关系
     */
    private Map<Class<? extends Annotation>, Set<Class<?>>> annotationClassMap = new HashMap<>();

    /**
     * 构造函数
     */
    public MZLApplicationContext() {
        super();
    }

    /**
     * 构造函数
     *
     * @param classLoader
     * @param packages    要扫描的包路径
     */
    public MZLApplicationContext(ClassLoader classLoader, String[] packages) {
        super(classLoader, packages);
    }

    /**
     * 构造函数
     *
     * @param classLoader
     * @param scannerPkg  包扫描器
     */
    public MZLApplicationContext(ClassLoader classLoader, ScannerPkg scannerPkg) {
        super(classLoader, scannerPkg);
    }

    /**
     * 构造函数
     *
     * @param classLoader
     * @param packages    要扫描的包路径
     * @param scannerPkg  包扫描器
     */
    public MZLApplicationContext(ClassLoader classLoader, String[] packages, ScannerPkg scannerPkg) {
        super(classLoader, packages, scannerPkg);
    }

    /**
     * 获取指定注解对应的所有类集合
     * @param annotationClass
     * @return
     */
    public Set<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotationClass){
        return annotationClassMap.get(annotationClass);
    }

    /**
     * 获取解析的类
     * @return
     */
    private Class<?> getMainClass(){
        ScannerPkg scannerPkg = getScannerPkg();
        if (scannerPkg instanceof ConfigurationScannerPkg){
            ConfigurationScannerPkg pkg = (ConfigurationScannerPkg) scannerPkg;
            return pkg.getParseClass();
        }
        return null;
    }

    /**
     * 对扫描出来的类进行扩展处理
     *
     * @param classes
     */
    @Override
    protected void afterProcess(Set<Class<?>> classes) {
        super.afterProcess(classes);

        //扩展应用
        StopWatch stopWatch = new StopWatch();
        if (LOGGER.isDebugEnabled()){
            stopWatch.start();
            LOGGER.debug("开始把解析的类与注解映射关联。。。");
        }
        Set<Class<? extends Annotation>> annotationKeys = new HashSet<>(getAnnotationKeys());
        Class<?> mainClass = getMainClass();
        if (mainClass != null) {
            AnnotationKeys keys = mainClass.getAnnotation(AnnotationKeys.class);
            if (keys != null){
                // 记入额外的key与类型映射
                Class<? extends Annotation>[] annotations = keys.annotations();
                annotationKeys.addAll(Arrays.asList(annotations));
                for (Class<?> cs : classes) {
                    for (Class<? extends Annotation> annotation : annotationKeys) {
                        if (cs.getAnnotation(annotation) != null){
                            Set<Class<?>> cls = annotationClassMap.computeIfAbsent(annotation, key -> new HashSet<>());
                            cls.add(cs);
                        }
                    }
                }
            }
        }

        if (LOGGER.isDebugEnabled()){
            LOGGER.debug("注解与类映射关联完成，使用时间是：" + stopWatch.stopAndFormatter());
        }
    }

    /**
     * 创建上下文
     * @param parseClass 要解析的配置类，通过该配置了加载到哪些包需要扫描
     * @return 上下文
     * @throws NullPointerException 假如参数为null，则抛出该异常
     */
    public static ApplicationContext create(Class<?> parseClass) throws ApplicationContextException {
        return create(parseClass, MZLApplicationContext.class.getClassLoader());
    }

    /**
     * 创建上下文
     * @param parseClass 要解析的配置类，通过该配置了加载到哪些包需要扫描
     * @return 上下文
     * @throws NullPointerException 假如第一个参数为null，则抛出该异常
     */
    public static ApplicationContext create(Class<?> parseClass, ClassLoader classLoader)
            throws ApplicationContextException {
        AssertUtils.isNotNull(parseClass, "parseClass parameter must not be null!");
        ApplicationContext context = new MZLApplicationContext(classLoader, new ScannerAnnotationParser(classLoader, parseClass))
                .complete();
        //把创建好的上下文放入缓存中
        ApplicationContextUtils.pushContext(context);
        return context;
    }
}
